/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*                                                                           */
/*    Copyright (C) 2005 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    drvPWMSound.c - PWM based Sound Output Driver                          */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include <windows.h>
#include <fclMultimedia.hpp>

extern "C"
{
#include "sndWave.h"
#include "krnlResourceFile.h"
}

///////////////////////////////////////////////////////////////////////////////
// Defines

///////////////////////////////////////////////////////////////////////////////
// Waveout Class
class emuPWMWaveOut : public mmWaveOut
{
  public:
    emuPWMWaveOut(void);

  protected:
    bool FillBuffer( mmWaveBuffer* in_size );
};

///////////////////////////////////////////////////////////////////////////////
// Module local variables
static emuPWMWaveOut l_waveout;
static volatile dosHandle l_position = 0;
static volatile dosWord l_remaining = 0;
static dosROMAddress l_wave_resource_address = 0;


///////////////////////////////////////////////////////////////////////////////
// Constructor
emuPWMWaveOut::emuPWMWaveOut(void)
{
}

///////////////////////////////////////////////////////////////////////////////
// Callback
bool emuPWMWaveOut::FillBuffer( mmWaveBuffer* in_buffer )
{
  int buffer_pos = 0;

  // fill out buffer
  while( buffer_pos < in_buffer->Buffer.GetSize() && l_remaining > 0 )
  {
		in_buffer->Buffer[buffer_pos] = dosROMReadByte( l_position );
		l_position++;
		l_remaining--;
    buffer_pos++;
  }

  // prepare header
  if( buffer_pos > 0 )
  {
    in_buffer->Header.dwBufferLength = buffer_pos;

    return true;
  }
  else
    return false;
}

///////////////////////////////////////////////////////////////////////////////
// Initialize wave device
extern "C" void sndInitWaveDevice(void)
{
  mmWaveFormat wave_format;

	// init wave resource address
  l_wave_resource_address = krnlGetResourceAddress( 0x45564157ul );

  // init waveout device
  wave_format.SampleRate    = 8000;
	wave_format.BitsPerSample = 8;
	wave_format.ChannelCount  = 1;

  l_waveout.Open( WAVE_MAPPER, wave_format ); 
}

///////////////////////////////////////////////////////////////////////////////
// Play wave
extern "C" dosBool sndStartWaveOut( dosHandle in_wave_handle )
{
  dosROMAddress address;

  // if wave out is active stop it
  l_waveout.Stop();

  // if no wave chunk in the resource file
	if( l_wave_resource_address == 0 )
		return dosFalse;

	address = l_wave_resource_address + in_wave_handle;

	// check format
	if( dosROMReadByte( address++ ) != 1 )
		return dosFalse;

	// load size
	l_remaining = (dosWord)(dosROMReadDWord( address ) );

	// address of wave data
	l_position = address + (dosHandle)sizeof( dosDWord );

  // start
  l_waveout.Start();

	return dosTrue;
}

///////////////////////////////////////////////////////////////////////////////
// Is Wave Out Busy
extern "C" dosBool sndIsWaveOutBusy(void)
{
	return l_waveout.IsBusy();
}

///////////////////////////////////////////////////////////////////////////////
// Stop Wave Out
extern "C" void sndStopWaveOut(void)
{
	l_remaining = 0;

  l_waveout.Stop();
}
